package cn.tqfeiyang.smartadmin.commons.application;

import cn.dev33.satoken.annotation.*;
import cn.dev33.satoken.strategy.SaStrategy;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.HandlerMethod;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;

@Configuration
public class SwaggerConfiguration {

    public static final String[] SWAGGER_WHITELIST = {
            "/swagger-ui/**",
            "/swagger-ui/index.html",
            "/swagger-ui.html",
            "/swagger-ui.html/**",
            "/v3/api-docs",
            "/v3/api-docs/**",
            "/doc.html",
    };

    @Value("${sa-token.token-name}")
    private String tokenName;

    private String SCHEMA_KEY = "token";

    @Bean
    public OpenAPI swaggerOpenAPI() {
        Info info = new Info().title("系统接口文档")
                .version("v2.7.18");

//        SecurityScheme securityScheme = new SecurityScheme()
//                .type(SecurityScheme.Type.HTTP)
//                .scheme("bearer")
//                .bearerFormat("JWT")
//                .in(SecurityScheme.In.HEADER)
//                .name("jwt");
//
//        Components components = new Components()
//                //.addSecuritySchemes("bearer-jwt", securityScheme);
//                .addSecuritySchemes(Constants.AUTH_TOKEN_HEADER, securityScheme);

        SecurityScheme securityScheme = new SecurityScheme()
                .type(SecurityScheme.Type.APIKEY)
                .in(SecurityScheme.In.HEADER)
                .name(tokenName);

        Components components = new Components()
                .addSecuritySchemes(SCHEMA_KEY, securityScheme);

        return new OpenAPI()
                .info(info)
                .components(components);
    }

    @Bean
    public GroupedOpenApi allApi() {
        return GroupedOpenApi.builder()
                .group("default")
                .pathsToExclude("/api/auth/**", "/api/echo/**")
                .addOperationCustomizer(customize)
                .build();
    }

    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .group("public")
                .pathsToMatch("/api/auth/**", "/api/echo/**")
                .addOperationCustomizer(customize)
                .build();
    }

    private OperationCustomizer customize = new OperationCustomizer() {
        @Override
        public Operation customize(Operation operation, HandlerMethod handlerMethod) {
            // 检查控制器方法或其所属的控制器类是否有 @SaIgnore 注解，可以匿名访问
            if (SaStrategy.instance.isAnnotationPresent.apply(handlerMethod.getMethod(), SaIgnore.class)) {
                return operation;
            }


            // 如果存在下列这些注解中的任意一个，都需要传递 token
            List<Class<? extends Annotation>> list = Arrays.asList(
                    SaCheckLogin.class,
                    SaCheckPermission.class,
                    SaCheckRole.class,
                    SaCheckSafe.class,
                    SaCheckDisable.class,
                    SaCheckHttpBasic.class,
                    SaCheckHttpDigest.class,
                    SaCheckOr.class);
            for (Class<? extends Annotation> annotationClass : list) {
                if (SaStrategy.instance.isAnnotationPresent.apply(handlerMethod.getMethod(), annotationClass)) {
                    operation.addSecurityItem(new SecurityRequirement().addList(SCHEMA_KEY));
                }
            }

            return operation;
        }
    };
}
